//@formatter:off
/*********************************************************************************************************************************************************************************
 * #######################
 * #   FILE DESCRIPTOR   #
 * #######################
 * Application: BiblioteQOnline
 * Package: org.biblioteq.web.backing
 * File: A_ManageUsers_Backing.java
 * 
 * #######################
 * #   GNU DISCLAIMER    #
 * ####################### 
 * BiblioteQ Online is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version. BiblioteQ Online is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
 * 
 * #######################
 * #       Purpose       #
 * #######################
 * Provides methods that back all manage users functions.
 *
 * #######################
 * #      Revision       #
 * ####################### 
 * Jun 2, 2012, Clinton Bush, 1.0.0,
 *    New file.
 * 
 ********************************************************************************************************************************************************************************** 
 */
//@formatter:on
package org.biblioteq.web.backing;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.AjaxBehaviorEvent;

import org.apache.log4j.Logger;
import org.biblioteq.ejb.entities.User;
import org.biblioteq.ejb.interfaces.MemberBusinessLocal;
import org.biblioteq.ejb.interfaces.UserBusinessLocal;
import org.biblioteq.web.common.Constants;
import org.biblioteq.web.model.ValidationMessage_Model;
import org.richfaces.component.UIExtendedDataTable;

/**
 * Provides methods that back all manage users functions.
 * 
 * @author Clint Bush
 * 
 */
@ManagedBean(name = "A_ManageUsers_Backing")
@ViewScoped
public class A_ManageUsers_Backing implements Serializable
{
	/**
	 * GUID for implementing Serializable.
	 */
	private static final long serialVersionUID = 8394219864358204165L;
	
	/**
	 * Get the logger.
	 */
	private static Logger log = Logger.getLogger(A_ManageUsers_Backing.class);
	
	/**
	 * Get a copy of the Page_Backing bean. This will be injected via the setPageBacking(Page_Backing pageBacking) method.
	 */
	@ManagedProperty("#{Page_Backing}")
	private Page_Backing pageBacking;
	
	/**
	 * Get a reference to the Users EJB.
	 */
	@EJB(name = "UserBusiness")
	private UserBusinessLocal userEjb;
	
	/**
	 * Get a reference to the Member EJB.
	 */
	@EJB(name = "MemberBusiness")
	private MemberBusinessLocal memberEjb;
	
	/**
	 * Get the users.
	 */
	private List<User> users = new ArrayList<User>();
	
	/**
	 * Stores the row key items generated when a admin makes a selection. This allows us to populate the selectedUsers list with the items currently selected.
	 */
	private Collection<Object> usersSelection = new ArrayList<Object>();
	
	/**
	 * Stores the item currently selected by the admin in the users table.
	 */
	private List<User> selectedUsers = new ArrayList<User>();
	
	/**
	 * Stores the user currently being edited.
	 */
	private User currentlySelectedUser = new User();
	
	/**
	 * Indicates if the user editor should be shown.
	 */
	private boolean isEditorShown = false;
	
	/**
	 * Indicates if the password should be validated for change.
	 */
	private boolean isChangePassword = false;
	
	private String password1 = "";
	private String password2 = "";
	
	/**
	 * Get the utility for handling error messages.
	 */
	ValidationMessage_Model errorMessages = new ValidationMessage_Model();
	
	/**
	 * Event listener for the "Cancel" button on the User Editor.
	 * 
	 * @param e
	 *            (AjaxBehaviorEvent) The ActionEvent object generated by the component that called this method.
	 */
	public void closeUserEditorListener(AjaxBehaviorEvent e)
	{
		this.currentlySelectedUser = null;
		this.isEditorShown = false;
	}
	
	/**
	 * Returns the currently selected user; returns null if the editor should be closed.
	 * 
	 * @return the currentlySelectedUser
	 */
	public User getCurrentlySelectedUser()
	{
		if (this.currentlySelectedUser == null)
		{
			A_ManageUsers_Backing.log.info("User is null.");
		}
		return this.currentlySelectedUser;
	}
	
	/**
	 * Returns the first password of the new password.
	 * 
	 * @return the password1
	 */
	public String getPassword1()
	{
		return this.password1;
	}
	
	/**
	 * Returns the verification password of the new password.
	 * 
	 * @return the password2
	 */
	public String getPassword2()
	{
		return this.password2;
	}
	
	/**
	 * Returns a list of all users.
	 * 
	 * @return (List<User>) The users.
	 */
	public List<User> getUsers()
	{
		return this.users;
	}
	
	/**
	 * Returns a collection of items that are selected in the "Users" table.
	 * 
	 * @return the usersSelection
	 */
	public Collection<Object> getUsersSelection()
	{
		return this.usersSelection;
	}
	
	/**
	 * Navigates the user to the Manage Users page.
	 */
	public void gotoManageUsers(ActionEvent e)
	{
		this.pageBacking.setRenderPage(Constants.PAGE_ADMIN_MANAGEUSERS);
	}
	
	/**
	 * Perform initialization tasks.
	 */
	@PostConstruct
	public void init()
	{
		this.users = this.userEjb.getAllUsers();
	}
	
	/**
	 * True if the admin chose to change the password; false, otherwise.
	 * 
	 * @return the isChangePassword
	 */
	public boolean isChangePassword()
	{
		return this.isChangePassword;
	}
	
	/**
	 * Indicates if the user editor should be shown.
	 * 
	 * @return the isEditorShown
	 */
	public boolean isEditorShown()
	{
		return this.isEditorShown;
	}
	
	/**
	 * Saves the changes to the currentlySelectedUser and then sets it to null to close it.
	 * 
	 * @param e
	 *            (AjaxBehaviorEvent) The ActionEvent object generated by the component that called this method.
	 */
	public void saveUserListener(AjaxBehaviorEvent e)
	{
		if (FacesContext.getCurrentInstance().getMessageList().size() < 1)
		{
			// Validate the Fields
			this.validate(this.currentlySelectedUser);
			
			// Check if our ValidationMessage_Model has any error messages
			if (!(this.errorMessages.hasMessages()))
			{
				// Save the changes
				this.currentlySelectedUser.setMember(this.memberEjb.saveMember(this.currentlySelectedUser.getMember()));
				this.userEjb.saveUser(this.currentlySelectedUser);
				
				// Re-initialize to get a clean copy of the users
				this.init();
				
				// Reset flags
				this.isEditorShown = false;
				this.isChangePassword = false;
				
				// Show a confirmation message
				this.pageBacking.showInfoMessage("Success!", "Your changes have been saved!");
			}
			else
			{
				// Render Error Messages and Refresh our User List to Remove temporary changes
				this.errorMessages.renderMessages();
				this.init();
				
				// Refresh the currently selected user to remove its temporary changes
				this.selectedUsers.set(0, this.userEjb.refreshUser(this.currentlySelectedUser));
				this.currentlySelectedUser = this.selectedUsers.get(0);
				
			}
		}
	}
	
	/**
	 * This is the event listener for row selections from the borrowed items table. It gets the selected row keys and then adds their corresponding items to the selectedItems List.
	 * 
	 * @param event
	 */
	public void selectionListener(AjaxBehaviorEvent event)
	{
		UIExtendedDataTable dataTable = (UIExtendedDataTable) event.getComponent();
		Object originalKey = dataTable.getRowKey();
		
		//@formatter:off
		this.selectedUsers.clear();
		for (Object selectionKey : this.usersSelection)
		{
			dataTable.setRowKey(selectionKey);
			
			if (dataTable.isRowAvailable())
			{
				this.selectedUsers.add((User) dataTable.getRowData());
			}
		}
		dataTable.setRowKey(originalKey);
		//@formatter:on
	}
	
	/**
	 * Sets if the admin is going to change the password.
	 * 
	 * @param isChangePassword
	 *            the isChangePassword to set
	 */
	public void setChangePassword(boolean isChangePassword)
	{
		this.isChangePassword = isChangePassword;
	}
	
	/**
	 * Sets the currently selected user.
	 * 
	 * @param currentlySelectedUser
	 *            the currentlySelectedUser to set
	 */
	public void setCurrentlySelectedUser(User currentlySelectedUser)
	{
		this.currentlySelectedUser = currentlySelectedUser;
	}
	
	/**
	 * @param pageBacking
	 *            the pageBacking to set
	 */
	public void setPageBacking(Page_Backing pageBacking)
	{
		this.pageBacking = pageBacking;
	}
	
	/**
	 * Sets the first password of the new password.
	 * 
	 * @param password1
	 *            the password1 to set
	 */
	public void setPassword1(String password1)
	{
		this.password1 = password1;
	}
	
	/**
	 * Sets the verification password of the new password.
	 * 
	 * @param password2
	 *            the password2 to set
	 */
	public void setPassword2(String password2)
	{
		this.password2 = password2;
	}
	
	/**
	 * Sets a list of all users.
	 * 
	 * @param users
	 *            (List<User>) The users to set.
	 */
	public void setUsers(List<User> users)
	{
		this.users = users;
	}
	
	/**
	 * Sets a collection of items that are selected in the "Users" table.
	 * 
	 * @param usersSelection
	 *            the usersSelection to set
	 */
	public void setUsersSelection(Collection<Object> usersSelection)
	{
		this.usersSelection = usersSelection;
	}
	
	/**
	 * Validate the fields prior to saving.
	 * 
	 * @return (boolean)
	 */
	public void validate(User userToValidate)
	{
		/*
		 * USERNAME
		 */
		User userWithUsername = this.userEjb.getUser(userToValidate.getUserName());
		if (userWithUsername != null && userWithUsername.getId() != userToValidate.getId())
		{
			this.errorMessages.addMessage("The User Name has been changed to a non-unique username and cannot be saved.");
		}
		
		if (userToValidate.getUserName().length() < 1)
		{
			this.errorMessages.addMessage("The User Name cannot be empty.");
		}
		
		/*
		 * PASSWORD
		 */
		if (this.isChangePassword)
		{
			if (this.password1.length() < 1)
			{
				this.errorMessages.addMessage("Your new password must not be blank.");
			}
			else
				if (!(this.password1.equals(this.password2)))
				{
					this.errorMessages.addMessage("The new password and verification password do not match.");
				}
				else
				{
					userToValidate.setPassword(this.password1);
				}
		}
		
		/*
		 * FIRST AND LAST NAME
		 */
		if (userToValidate.getMember().getFirstName().length() < 1 || userToValidate.getMember().getLastName().length() < 1)
		{
			this.errorMessages.addMessage("First and Last Name Fields cannot be blank.");
		}
		
		/*
		 * STREET ADDRESS
		 */
		if (userToValidate.getMember().getStreetAddress().length() < 1)
		{
			this.errorMessages.addMessage("The Street Address Field cannot be blank.");
		}
		
		/*
		 * CITY
		 */
		if (userToValidate.getMember().getCity().length() < 1)
		{
			this.errorMessages.addMessage("The City Field cannot be blank.");
		}
		
		/*
		 * ZIP
		 */
		if (userToValidate.getMember().getZip().length() < 1)
		{
			this.errorMessages.addMessage("The ZIP Field cannot be blank.");
		}
		
		/*
		 * PHONE
		 */
		if (userToValidate.getMember().getTelephone().length() < 1)
		{
			this.errorMessages.addMessage("The Phone Field cannot be blank.");
		}
		
		/*
		 * E-MAIL
		 */
		if (userToValidate.getMember().getEmail().length() < 1)
		{
			this.errorMessages.addMessage("The E-Mail Field cannot be blank.");
		}
	}
	
	/**
	 * Event listener for the "View User" button.
	 * 
	 * @param e
	 *            (AjaxBehaviorEvent) The ActionEvent object generated by the component that called this method.
	 */
	public void viewUserListener(AjaxBehaviorEvent e)
	{
		if (this.selectedUsers.size() > 0)
		{
			this.currentlySelectedUser = this.selectedUsers.get(0);
			this.isEditorShown = true;
		}
	}
}
